#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED

// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities
//! that can be useful in certain simple scenarios. They should probably not be
//! used if maximizing performance is the main objective.

#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "rapidxml.hpp"

namespace rapidxml {

//! Represents data loaded from a file
template <class Ch = char>
class file {
 public:
  //! Loads file into the memory. Data will be automatically destroyed by the
  //! destructor. \param filename Filename to load.
  file(const char *filename) {
    using namespace std;

    // Open stream
    basic_ifstream<Ch> stream(filename, ios::binary);
    if (!stream) throw runtime_error(string("cannot open file ") + filename);
    stream.unsetf(ios::skipws);

    // Determine stream size
    stream.seekg(0, ios::end);
    size_t size = stream.tellg();
    stream.seekg(0);

    // Load data and add terminating 0
    m_data.resize(size + 1);
    stream.read(&m_data.front(), static_cast<streamsize>(size));
    m_data[size] = 0;
  }

  //! Loads file into the memory. Data will be automatically destroyed by the
  //! destructor \param stream Stream to load from
  file(std::basic_istream<Ch> &stream) {
    using namespace std;

    // Load data and add terminating 0
    stream.unsetf(ios::skipws);
    m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
    if (stream.fail() || stream.bad())
      throw runtime_error("error reading stream");
    m_data.push_back(0);
  }

  //! Gets file data.
  //! \return Pointer to data of file.
  Ch *data() { return &m_data.front(); }

  //! Gets file data.
  //! \return Pointer to data of file.
  const Ch *data() const { return &m_data.front(); }

  //! Gets file data size.
  //! \return Size of file data, in characters.
  std::size_t size() const { return m_data.size(); }

 private:
  std::vector<Ch> m_data;  // File data
};

//! Counts children of node. Time complexity is O(n).
//! \return Number of children of node
template <class Ch>
inline std::size_t count_children(xml_node<Ch> *node) {
  xml_node<Ch> *child = node->first_node();
  std::size_t count = 0;
  while (child) {
    ++count;
    child = child->next_sibling();
  }
  return count;
}

//! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node
template <class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node) {
  xml_attribute<Ch> *attr = node->first_attribute();
  std::size_t count = 0;
  while (attr) {
    ++count;
    attr = attr->next_attribute();
  }
  return count;
}

}  // namespace rapidxml

#endif
